package hip.util;

import com.alibaba.fastjson.JSON;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class WsClient {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final String endpoint;
    private final String namespace;
    private final boolean addNamespace;

    public WsClient(String endpoint, String namespace) {
        this.endpoint = endpoint;
        this.namespace = namespace;
        this.addNamespace=true;
    }

    public WsClient(String endpoint, String namespace, boolean paramsAddNamespace) {
        this.endpoint = endpoint;
        this.namespace = namespace;
        this.addNamespace=paramsAddNamespace;
    }

    private EndpointReference getEndpointReference(){
        return new EndpointReference(endpoint);
    }
    private OMNamespace getOMNamespace(OMFactory fac){
        return fac.createOMNamespace(namespace, "tns");
    }
    private OMElement invokeMethod(String methodName, Map<String, Object> params){
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMNamespace omNs = getOMNamespace(fac);

        OMElement method = fac.createOMElement(methodName, omNs);
        if(null!=params&&!params.isEmpty()){
            for(Map.Entry<String, Object> item: params.entrySet()){
                OMElement value;
                if (addNamespace){
                    value= fac.createOMElement(item.getKey(), omNs);
                }else {
                    value = fac.createOMElement(item.getKey(), null);
                }
                value.addChild(fac.createOMText(value, toString(item.getValue())));
                method.addChild(value);
            }
        }

        return method;
    }


    private String toString(Object obj){
        // 可扩展的toString方法
        return obj.toString();
    }
    public void fireAndForget(String methodName, Map<String, Object> params) throws AxisFault {
        logger.info("fireAndForget...");
        logger.info("methodName: "+methodName);
        logger.info("params: "+params);
        Options options = new Options();
        options.setTo(getEndpointReference());
        options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

        ServiceClient sender = new ServiceClient();
        sender.setOptions(options);

        sender.fireAndForget(invokeMethod(methodName, params));
    }
    public Map<String, String> sendReceive(String methodName, Map<String, Object> params) throws Exception {
        return sendReceive(methodName, params, null);
    }
    public Map<String, String> sendReceive(String methodName, Map<String, Object> params, String action) throws Exception {
        logger.info("sendReceive...");
        logger.info("methodName: "+methodName);
        logger.info("params: "+params);
        Options options = new Options();
        options.setTo(getEndpointReference());
        options.setTransportInProtocol(Constants.TRANSPORT_HTTPS);


        if(StringUtils.hasText(action)){
            options.setAction(action);
        }

        ServiceClient sender = new ServiceClient();
        sender.setOptions(options);

        OMElement receive = sender.sendReceive(invokeMethod(methodName, params));
        Iterator<OMElement> elements = receive.getChildElements();
        Map<String, String> result = new HashMap<>();
        while (elements.hasNext()){
            OMElement element = elements.next();
            result.put(element.getLocalName(), element.getText());
        }
        logger.info(JSON.toJSONString(result));
        if(result.isEmpty()){
            logger.warn("result is empty!");
        }
        // 解析?
        return result;
    }


}
